package com.mico.echart.monitor.system;

import com.mico.echart.monitor.config.GlobalObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StopWatch;

import java.lang.management.*;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author micocube
 * projectName: utils4j
 * packageName: com.coding.system
 * email: ldscube@gmail.com
 * createTime: 2019-12-27 16:52
 * version: 0.1
 * description:
 */
public class JvmInfo {
    private static final Logger logger = LoggerFactory.getLogger(JvmInfo.class);


    public static Map<String, Number> collectThreadInfo() {
        final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        ThreadInfo[] threadInfos = threadBean.getThreadInfo(threadBean.getAllThreadIds());
        Map<String, Number> map = new LinkedHashMap<String, Number>();
        map.put("jvm.thread.count", threadBean.getThreadCount());
        map.put("jvm.thread.daemon.count", threadBean.getDaemonThreadCount());
        map.put("jvm.thread.totalstarted.count", threadBean.getTotalStartedThreadCount());


        int newThreadCount = 0;
        int runnableThreadCount = 0;
        int blockedThreadCount = 0;
        int waitThreadCount = 0;
        int timeWaitThreadCount = 0;
        int terminatedThreadCount = 0;

        if (threadInfos != null) {
            for (ThreadInfo threadInfo : threadInfos) {
                if (threadInfo != null) {
                    logger.info(threadInfo.toString());
                    logger.info(Arrays.toString(threadInfo.getStackTrace()));
                    switch (threadInfo.getThreadState()) {
                        case NEW:
                            newThreadCount++;
                            break;
                        case RUNNABLE:
                            runnableThreadCount++;
                            break;
                        case BLOCKED:
                            blockedThreadCount++;
                            break;
                        case WAITING:
                            waitThreadCount++;
                            break;
                        case TIMED_WAITING:
                            timeWaitThreadCount++;
                            break;
                        case TERMINATED:
                            terminatedThreadCount++;
                            break;
                        default:
                            break;
                    }
                } else {
                    /*
                     * If a thread of a given ID is not alive or does not exist,
                     * the corresponding element in the returned array will,
                     * contain null,because is mut exist ,so the thread is terminated
                     */
                    terminatedThreadCount++;
                }
            }
        }

        map.put("jvm.thread.new.count", newThreadCount);
        map.put("jvm.thread.runnable.count", runnableThreadCount);
        map.put("jvm.thread.blocked.count", blockedThreadCount);
        map.put("jvm.thread.waiting.count", waitThreadCount);
        map.put("jvm.thread.time_waiting.count", timeWaitThreadCount);
        map.put("jvm.thread.terminated.count", terminatedThreadCount);

        long[] ids = threadBean.findDeadlockedThreads();
        map.put("jvm.thread.deadlock.count", ids == null ? 0 : ids.length);

        return map;
    }


    private static Map<String, Number> collectClassLoadingInfo() {

        ClassLoadingMXBean classLoadingMXBean = ManagementFactory.getClassLoadingMXBean();
        Map<String, Number> map = new LinkedHashMap<String, Number>();

        map.put("jvm.classloading.loaded.count", classLoadingMXBean.getLoadedClassCount());
        map.put("jvm.classloading.totalloaded.count", classLoadingMXBean.getTotalLoadedClassCount());
        map.put("jvm.classloading.unloaded.count", classLoadingMXBean.getUnloadedClassCount());


        return map;
    }


    public static void main(String[] args) {
        StopWatch stopWatch = new StopWatch("vm_task");
        stopWatch.start("classLoading");
        Map<String, Number> classLoadingInfo = JvmInfo.collectClassLoadingInfo();
        logger.info(GlobalObject.writeValueAsString(classLoadingInfo,true));
        stopWatch.stop();

        stopWatch.start("threadInfo");
        Map<String, Number> collectThreadInfo = JvmInfo.collectThreadInfo();
        logger.info(GlobalObject.writeValueAsString(collectThreadInfo,true));
        stopWatch.stop();


        stopWatch.start("gc");
        GarbageCollectorInfo garbageCollectorInfo = new GarbageCollectorInfo();
        Map<String, Number> collectGC = garbageCollectorInfo.collectGC();
        logger.info(GlobalObject.writeValueAsString(collectGC,true));
        stopWatch.stop();


        stopWatch.start("memory");
        MemoryInformation memoryInformation = new MemoryInformation();
        Map<String, String> collect = memoryInformation.collect();
        logger.info(GlobalObject.writeValueAsString(collect,true));
        stopWatch.stop();


        stopWatch.start("system");
        SystemInfoTest.collect();
        stopWatch.stop();


        List<MemoryManagerMXBean> managerMXBeans = ManagementFactory.getMemoryManagerMXBeans();
        List<MemoryPoolMXBean> beans = ManagementFactory.getMemoryPoolMXBeans();

        System.out.println(beans);


        System.out.println(stopWatch.prettyPrint());
    }




}
